#include <Globals.h>
#include <SyscallDispatcher.h>
#include <ProcessManager.h>
#include <MonitorDriver.h>
#include <Resource.h>
#include <RemoteResource.h>
#include <ResourceManager.h>

s32int syscall(u32int id)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id));
  return ret;
}

s32int syscall1(u32int id, s32int val)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val));
  return ret;
}

s32int syscall2(u32int id, s32int val1, s32int val2)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val1), "c"(val2));
  return ret;
}

s32int syscall3(u32int id, s32int val1, s32int val2, s32int val3)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val1), "c"(val2), "d"(val3));
  return ret;
}

s32int syscall4(u32int id, s32int val1, s32int val2, s32int val3, s32int val4)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val1), "c"(val2), "d"(val3), "S"(val4));
  return ret;
}

s32int syscall5(u32int id, s32int val1, s32int val2, s32int val3, s32int val4, s32int val5)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val1), "c"(val2), "d"(val3), "S"(val4), "D"(val5));
  return ret;
}

SyscallDispatcher::SyscallDispatcher()
 : InterruptServiceRoutine()
{
}


SyscallDispatcher::~SyscallDispatcher()
{
}

void SyscallDispatcher::run(Registers *r)
{

  // Was this a resource call request?
  if (r->int_no == 50)
  {
    // Get the resource.
    Resource *resource = resourceManager.request(r->eax);
    if (!resource)
    {
      r->eax = -1;
      r->ecx = processManager->getProcess()->getErrno();
    }
    else
    {
      DEBUG_SPAM("Calling function " << dec << r->ebx << "on resource: " << r->eax);
      
      r->eax = resource->callSys(r->ebx, true, r->ecx, r->edx, r->esi, r->edi);
      r->ecx = processManager->getProcess()->getErrno();
    }
    return;
  }
  // Was this an asynchronous resource all request?
  if (r->int_no == 51)
  {
    // Get the resource.
    Resource *resource = resourceManager.request(r->eax);
    if (!resource)
    {
      r->eax = -1;
      r->ecx = processManager->getProcess()->getErrno();
    }
    else
    {
      DEBUG_SPAM("Calling function " << dec << r->ebx << " on resource: " << r->eax << " Asynchronously.");
      r->eax = resource->callSys(r->ebx, false, r->ecx, r->edx, r->esi, r->edi);
      r->ecx = processManager->getProcess()->getErrno();
    }
    return;
  }

  switch(r->eax)
  {
  case SYSCALL_FORK:
    r->eax = processManager->getProcess()->fork();
    break;
  
  case SYSCALL_EXECVE:
    processManager->getProcess()->execve2((char*)r->ebx, (char**)r->ecx, (char**)r->edx);
    break;

  case SYSCALL_EXIT:
    processManager->getProcess()->exit(r->ebx);
    break;

  case SYSCALL_YIELD:
    processManager->yield(-1);
    break;

  case SYSCALL_YIELDTO:
    processManager->yield(r->ebx);
    break;

  case SYSCALL_NULL:
    break;

  case SYSCALL_REQUEST:
  {
    Resource *res = resourceManager.request((const char *)r->ebx);
    if (res)
      r->eax = res->getId();
    else
      r->eax = -1;
    break;
  }
  case SYSCALL_MORERPC:
    r->eax = (s32int)processManager->getProcess()->moreRpc();
    break;

  case SYSCALL_CREATERESOURCE:
  {
    RemoteResource *res = new RemoteResource((Callable*)r->ecx, (const char*)r->ebx);
    r->eax = (int) res->getId();
    break;
  }

  case SYSCALL_DESTROYRESOURCE:
    delete resourceManager.request(r->ebx);
    r->eax = (int)0;
    return;

  case SYSCALL_ADDFUNC0:
    resourceManager.request(r->ebx)->add(*(Resource::Call0*)r->ecx, r->edx);
    r->eax = (int)0;
    break;
  case SYSCALL_ADDFUNC1:
    resourceManager.request(r->ebx)->add(*(Resource::Call1*)r->ecx, r->edx);
    r->eax = (int)0;
    break;
  case SYSCALL_ADDFUNC2:
    resourceManager.request(r->ebx)->add(*(Resource::Call2*)r->ecx, r->edx);
    r->eax = (int)0;
    break;
  case SYSCALL_ADDFUNC3:
    resourceManager.request(r->ebx)->add(*(Resource::Call3*)r->ecx, r->edx);
    r->eax = (int)0;
    break;
  case SYSCALL_ADDFUNC4:
    resourceManager.request(r->ebx)->add(*(Resource::Call4*)r->ecx, r->edx);
    r->eax = (int)0;
    break;
  case SYSCALL_ADDFUNC5:
    resourceManager.request(r->ebx)->add(*(Resource::Call5*)r->ecx, r->edx);
    r->eax = (int)0;
    break;

  case SYSCALL_UFREE:
    memoryManager.ufree((void*)r->ebx);
    break;

  default:
    ASSERT(false);
  }
  r->ebx = processManager->getProcess()->getErrno();
}
